#ifndef MYURB_H
#define MYURB_H

#include "MyPacketProcessor.h"

typedef enum _USBD_PIPE_TYPE
{
    UsbdPipeTypeControl       = 0,
    UsbdPipeTypeIsochronous   = 1,
    UsbdPipeTypeBulk          = 2,
    UsbdPipeTypeInterrupt     = 3 
} USBD_PIPE_TYPE;

struct MY_USBD_PIPE_INFORMATION
{
    unsigned short     MaximumPacketSize;
    unsigned char      EndpointAddress;
    unsigned char      Interval;
    USBD_PIPE_TYPE     PipeType;
    unsigned long      PipeHandle;
    unsigned long      MaximumTransferSize;
    unsigned long      PipeFlags;
};

struct MY_USBD_ISO_PACKET_DESCRIPTOR
{
    unsigned long  Offset;
    unsigned long  Length;
    long           Status;
};

struct MY_USB_CONFIGURATION_DESCRIPTOR
{
    unsigned char   bLength;
    unsigned char   bDescriptorType;
    unsigned short  wTotalLength;
    unsigned char   bNumInterfaces;
    unsigned char   bConfigurationValue;
    unsigned char   iConfiguration;
    unsigned char   bmAttributes;
    unsigned char   MaxPower;
};

struct MY_USBD_INTERFACE_INFORMATION
{
    unsigned short    Length;
    unsigned char     InterfaceNumber;
    unsigned char     AlternateSetting;
    unsigned char     Class;
    unsigned char     SubClass;
    unsigned char     Protocol;
    unsigned long     InterfaceHandle;
    unsigned long     NumberOfPipes;

	std::vector<MY_USBD_PIPE_INFORMATION> Pipes; // Variable length array
};

struct MY_URB_HEADER
{
    unsigned short    Length;
    unsigned short    Function;
    long              Status;       
    unsigned long     UsbdDeviceHandle;
    unsigned long     UsbdFlags;	
};


//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////


class MY_URB : public MyPacket
{
public:
	//virtual void Deserialize(void *pBuffer, long bufSize, unsigned char packType) = 0;
	//std::wstring GetPacketName(){return packetName;}

protected:
    void DeserializeHeader(unsigned char packType);

	//std::wstring packetName;
    MyBuffer buffer;
    MY_URB_HEADER Hdr;
    bool isCompleted;
};

class MY_URB_WITH_TRANSFER_BUFFER : public MY_URB
{
public:
	~MY_URB_WITH_TRANSFER_BUFFER()
	{
		if (TransferBuffer != NULL)
		{
			delete[] TransferBuffer;
		}
		if (TransferBufferMDL != NULL)
		{
			delete[] TransferBufferMDL;
		}
	}

	MY_URB_WITH_TRANSFER_BUFFER()
	{
		TransferBuffer    = NULL;
		TransferBufferMDL = NULL;
	}

protected:
    bool thereIsAnMDL;

    unsigned long TransferBufferLength;
    unsigned char *TransferBuffer;
    unsigned char *TransferBufferMDL;

    void DeserializeTransferBuffer();
    std::wstring PrintTransferFlags(unsigned long TransferFlags);
    std::wstring PrintTransferBuffer();
};

class MY_URB_SELECT_INTERFACE : public MY_URB
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned long              ConfigurationHandle;
    MY_USBD_INTERFACE_INFORMATION Interface;
};

class MY_URB_SELECT_CONFIGURATION : public MY_URB
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();
    MY_URB_SELECT_CONFIGURATION();

private:
    bool bConfigurationDescriptor; // Used for serialization
    MY_USB_CONFIGURATION_DESCRIPTOR           ConfigurationDescriptor;
    unsigned long                             ConfigurationHandle;
    std::vector<MY_USBD_INTERFACE_INFORMATION> Interface; // Variable length array
};

class MY_URB_PIPE_REQUEST : public MY_URB
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned long PipeHandle;
};

class MY_URB_GET_CURRENT_FRAME_NUMBER : public MY_URB
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned long FrameNumber;
};

class MY_URB_CONTROL_TRANSFER : public MY_URB_WITH_TRANSFER_BUFFER
{
public:
    virtual void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

protected:
    unsigned long     PipeHandle;
    unsigned long     TransferFlags;	
    unsigned char     SetupPacket[8];	
}; 

class MY_URB_CONTROL_TRANSFER_EX : public MY_URB_CONTROL_TRANSFER
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned long Timeout;	
};

class MY_URB_BULK_OR_INTERRUPT_TRANSFER : public MY_URB_WITH_TRANSFER_BUFFER
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned long PipeHandle;
    unsigned long TransferFlags;
};

class MY_URB_ISOCH_TRANSFER : public MY_URB_WITH_TRANSFER_BUFFER
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned long    PipeHandle;
    unsigned long    TransferFlags;
    unsigned long    StartFrame;
    unsigned long    NumberOfPackets;
    unsigned long    ErrorCount;
    
    std::vector<MY_USBD_ISO_PACKET_DESCRIPTOR> IsoPacket; // Variable length array
};

class MY_URB_CONTROL_DESCRIPTOR_REQUEST : public MY_URB_WITH_TRANSFER_BUFFER
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned char   Index;
    unsigned char   DescriptorType;
    unsigned short  LanguageId;
    bool thereIsBuffer; // Used for serialization/deserialization
};

class MY_URB_CONTROL_GET_STATUS_REQUEST : public MY_URB_WITH_TRANSFER_BUFFER
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned short Index;
};

class MY_URB_CONTROL_FEATURE_REQUEST : public MY_URB
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned short  FeatureSelector;
    unsigned short  Index;;
};

class MY_URB_CONTROL_VENDOR_OR_CLASS_REQUEST : public MY_URB_WITH_TRANSFER_BUFFER
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned long   TransferFlags;
    unsigned char   RequestTypeReservedBits;
    unsigned char   Request;
    unsigned short  Value;
    unsigned short  Index;
};

class MY_URB_CONTROL_GET_INTERFACE_REQUEST : public MY_URB_WITH_TRANSFER_BUFFER
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned short  Interface;
};

class MY_URB_CONTROL_GET_CONFIGURATION_REQUEST : public MY_URB_WITH_TRANSFER_BUFFER
{
public:
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();
};

class MY_URB_OS_FEATURE_DESCRIPTOR_REQUEST : public MY_URB_WITH_TRANSFER_BUFFER
{
public:	
    void Deserialize (void *pBuffer, long bufSize, unsigned char packType);
    std::wstring GetDetailedInfo();

private:
    unsigned char   Recipient;
    unsigned char   InterfaceNumber;
    unsigned char   MS_PageIndex;
    unsigned short  MS_FeatureDescriptorIndex;
};

#endif // MYURB_H
